From 10a82268aa53afaaf62058acc256661b7d897994 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 7 Nov 2024 08:49:31 +0100 Subject: [PATCH 1/6] feat: negation requirement added to `Representation` concepts --- src/core/include/mp-units/framework/representation_concepts.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/include/mp-units/framework/representation_concepts.h b/src/core/include/mp-units/framework/representation_concepts.h index d802163d7..6a999516d 100644 --- a/src/core/include/mp-units/framework/representation_concepts.h +++ b/src/core/include/mp-units/framework/representation_concepts.h @@ -95,6 +95,7 @@ concept ScalarRepresentation = Scalar && WeaklyRegular && requires(T a, T { a / f } -> Scalar; // scalar operations + { -a } -> Scalar; { a + b } -> Scalar; { a - b } -> Scalar; { a* b } -> Scalar; @@ -112,6 +113,7 @@ concept ComplexRepresentation = Complex && WeaklyRegular && requires(T a, { a / T(f) } -> Complex; // complex operations + { -a } -> Complex; { a + b } -> Complex; { a - b } -> Complex; { a* b } -> Complex; @@ -134,6 +136,7 @@ concept VectorRepresentation = Vector && WeaklyRegular && requires(T a, T { a / f } -> Vector; // vector operations + { -a } -> Vector; { a + b } -> Vector; { a - b } -> Vector; // TBD From 34816574ca8864dbfda8a4dc68ee16e1b99ebf6a Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 7 Nov 2024 10:23:44 +0100 Subject: [PATCH 2/6] fix: missing `core.h` added to CMake --- src/core/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index fa6c7d954..0cc5b140f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -75,6 +75,7 @@ add_mp_units_module( include/mp-units/framework/value_cast.h include/mp-units/compat_macros.h include/mp-units/concepts.h + include/mp-units/core.h include/mp-units/framework.h MODULE_INTERFACE_UNIT mp-units-core.cpp ) From 8f062bfa87562056f4d43bcf14ddf14a5400f729 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 7 Nov 2024 10:24:28 +0100 Subject: [PATCH 3/6] refactor: mp_units.core defined in terms of `core.h` --- src/core/mp-units-core.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/core/mp-units-core.cpp b/src/core/mp-units-core.cpp index f56a846df..ac86fab8a 100644 --- a/src/core/mp-units-core.cpp +++ b/src/core/mp-units-core.cpp @@ -32,13 +32,4 @@ import std; #define MP_UNITS_IN_MODULE_INTERFACE -#include -#include -#include - -#if MP_UNITS_HOSTED -#include -#include -#include -#include -#endif +#include From 75b50b8d2c5dbeb5176332f3a34c08a0b2149863 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 7 Nov 2024 10:58:51 +0100 Subject: [PATCH 4/6] feat: `complex.h` added --- src/core/CMakeLists.txt | 3 +- src/core/include/mp-units/bits/core_gmf.h | 1 + src/core/include/mp-units/complex.h | 43 +++++++++++++++++++++++ src/core/include/mp-units/core.h | 1 + test/static/concepts_test.cpp | 9 ++--- test/static/quantity_test.cpp | 6 +--- 6 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 src/core/include/mp-units/complex.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0cc5b140f..2132d71ac 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -91,9 +91,10 @@ if(NOT ${projectPrefix}API_FREESTANDING) include/mp-units/bits/fmt.h include/mp-units/bits/requires_hosted.h include/mp-units/ext/format.h + include/mp-units/complex.h + include/mp-units/format.h include/mp-units/math.h include/mp-units/ostream.h - include/mp-units/format.h include/mp-units/random.h ) endif() diff --git a/src/core/include/mp-units/bits/core_gmf.h b/src/core/include/mp-units/bits/core_gmf.h index 5566bc923..d3a44fcbe 100644 --- a/src/core/include/mp-units/bits/core_gmf.h +++ b/src/core/include/mp-units/bits/core_gmf.h @@ -57,6 +57,7 @@ #ifndef MP_UNITS_IMPORT_STD #include #include +#include #include #include #include diff --git a/src/core/include/mp-units/complex.h b/src/core/include/mp-units/complex.h new file mode 100644 index 000000000..9f09c05f7 --- /dev/null +++ b/src/core/include/mp-units/complex.h @@ -0,0 +1,43 @@ +// 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 +// +#include +#include + +#ifndef MP_UNITS_IN_MODULE_INTERFACE +#ifdef MP_UNITS_IMPORT_STD +import std; +#else +#include +#endif +#endif + +namespace mp_units { + +template +constexpr bool is_complex> = true; + +} diff --git a/src/core/include/mp-units/core.h b/src/core/include/mp-units/core.h index 09ba3ac37..a99978f81 100644 --- a/src/core/include/mp-units/core.h +++ b/src/core/include/mp-units/core.h @@ -28,6 +28,7 @@ #include #if MP_UNITS_HOSTED +#include #include #include #include diff --git a/test/static/concepts_test.cpp b/test/static/concepts_test.cpp index c79e8851e..83ecfa0af 100644 --- a/test/static/concepts_test.cpp +++ b/test/static/concepts_test.cpp @@ -23,6 +23,9 @@ #include #include #include +#if MP_UNITS_HOSTED +#include +#endif #ifdef MP_UNITS_IMPORT_STD import std; #else @@ -35,12 +38,6 @@ import std; #endif #endif -#if MP_UNITS_HOSTED -template -constexpr bool mp_units::is_complex> = true; -#endif - - namespace { using namespace mp_units; diff --git a/test/static/quantity_test.cpp b/test/static/quantity_test.cpp index 16c6ab464..ba34a1601 100644 --- a/test/static/quantity_test.cpp +++ b/test/static/quantity_test.cpp @@ -29,6 +29,7 @@ #include #include #if MP_UNITS_HOSTED +#include #include #endif #ifdef MP_UNITS_IMPORT_STD @@ -45,11 +46,6 @@ import std; #endif #endif -#if MP_UNITS_HOSTED -template -constexpr bool mp_units::is_complex> = true; -#endif - template<> constexpr bool mp_units::is_vector = true; From da5034811581d699bd3830b640055214ef7ed63b Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 7 Nov 2024 18:39:32 +0100 Subject: [PATCH 5/6] feat: :boom: `RepresentationOf` concept now also accepts a `QuantitySpec` and accepts any representation character for quantity kinds --- .../character_of_a_quantity.md | 2 +- docs/users_guide/framework_basics/concepts.md | 19 ++++- .../framework_basics/design_overview.md | 4 +- .../simple_and_typed_quantities.md | 2 +- .../framework_basics/the_affine_space.md | 2 +- .../mp-units/framework/construction_helpers.h | 4 +- .../include/mp-units/framework/quantity.h | 78 +++++++++---------- .../mp-units/framework/quantity_concepts.h | 2 +- .../mp-units/framework/quantity_point.h | 10 +-- .../framework/quantity_point_concepts.h | 2 +- .../include/mp-units/framework/reference.h | 16 ++-- .../framework/representation_concepts.h | 9 ++- .../include/mp-units/framework/value_cast.h | 12 +-- test/static/quantity_test.cpp | 2 +- 14 files changed, 88 insertions(+), 76 deletions(-) diff --git a/docs/users_guide/framework_basics/character_of_a_quantity.md b/docs/users_guide/framework_basics/character_of_a_quantity.md index 90402906a..769fe55d8 100644 --- a/docs/users_guide/framework_basics/character_of_a_quantity.md +++ b/docs/users_guide/framework_basics/character_of_a_quantity.md @@ -148,7 +148,7 @@ As we remember, the `quantity` class template is defined as follows: ```cpp template Rep = double> + RepresentationOf Rep = double> class quantity; ``` diff --git a/docs/users_guide/framework_basics/concepts.md b/docs/users_guide/framework_basics/concepts.md index 797e7201a..c8177d39d 100644 --- a/docs/users_guide/framework_basics/concepts.md +++ b/docs/users_guide/framework_basics/concepts.md @@ -159,15 +159,28 @@ A `Reference` can either be: [value of a quantity](../../appendix/glossary.md#quantity-value). -### `RepresentationOf` { #RepresentationOf } +### `RepresentationOf` { #RepresentationOf } -`RepresentationOf` concept is satisfied by all `Representation` types that are of a specified -[quantity character](../../appendix/glossary.md#character) `Ch`. +`RepresentationOf` concept is satisfied: + +- if the type of `V` satisfies [`QuantitySpec`](#QuantitySpec): + + - by all [`Representation`](#Representation) types when `V` describes + a [quantity kind](../../appendix/glossary.md#kind), + - otherwise, by [`Representation`](#Representation) types that are of + a [quantity character](../../appendix/glossary.md#character) associated with a provided + quantity specification `V`. + +- if `V` is of `quantity_character` type: + + - by [`Representation`](#Representation) types that are of a provided + [quantity character](../../appendix/glossary.md#character). A user can declare a custom representation type to be of a specific character by providing the specialization with `true` for one or more of the following variable templates: - `is_scalar` +- `is_complex` - `is_vector` - `is_tensor` diff --git a/docs/users_guide/framework_basics/design_overview.md b/docs/users_guide/framework_basics/design_overview.md index 7446bea7f..3e5de7037 100644 --- a/docs/users_guide/framework_basics/design_overview.md +++ b/docs/users_guide/framework_basics/design_overview.md @@ -316,7 +316,7 @@ This is why a `quantity` class template is defined in the library as: ```cpp template Rep = double> + RepresentationOf Rep = double> class quantity; ``` @@ -365,7 +365,7 @@ In the **mp-units** library, the quantity point is implemented as: ```cpp template auto PO, - RepresentationOf Rep = double> + RepresentationOf Rep = double> class quantity_point; ``` diff --git a/docs/users_guide/framework_basics/simple_and_typed_quantities.md b/docs/users_guide/framework_basics/simple_and_typed_quantities.md index 178c36e24..dd7ee228a 100644 --- a/docs/users_guide/framework_basics/simple_and_typed_quantities.md +++ b/docs/users_guide/framework_basics/simple_and_typed_quantities.md @@ -20,7 +20,7 @@ In the **mp-units** library, a quantity is represented with the following class ```cpp template Rep = double> + RepresentationOf Rep = double> class quantity; ``` diff --git a/docs/users_guide/framework_basics/the_affine_space.md b/docs/users_guide/framework_basics/the_affine_space.md index 688c4379e..50a297722 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -96,7 +96,7 @@ origin: ```cpp template auto PO = default_point_origin(R), - RepresentationOf Rep = double> + RepresentationOf Rep = double> class quantity_point; ``` diff --git a/src/core/include/mp-units/framework/construction_helpers.h b/src/core/include/mp-units/framework/construction_helpers.h index 43eade949..36ffac6eb 100644 --- a/src/core/include/mp-units/framework/construction_helpers.h +++ b/src/core/include/mp-units/framework/construction_helpers.h @@ -39,7 +39,7 @@ namespace mp_units { template struct delta_ { - template Rep = std::remove_cvref_t> + template Rep = std::remove_cvref_t> [[nodiscard]] constexpr quantity operator()(FwdRep&& lhs) const { return quantity{std::forward(lhs), R{}}; @@ -48,7 +48,7 @@ struct delta_ { template struct absolute_ { - template Rep = std::remove_cvref_t> + template Rep = std::remove_cvref_t> [[nodiscard]] constexpr quantity_point operator()(FwdRep&& lhs) const { diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 8c265516c..bfd55b924 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -78,14 +78,15 @@ concept QuantityConvertibleTo = // deduced thus the function is evaluated here and may emit truncating conversion or other warnings) requires(QFrom q) { sudo_cast(q); }; -template -concept InvokeResultOf = std::regular_invocable && RepresentationOf, Ch>; +template +concept InvokeResultOf = QuantitySpec && std::regular_invocable && + RepresentationOf, QS>; template, - std::remove_const_t>::character> -concept InvocableQuantities = - Quantity && Quantity && InvokeResultOf; + auto QS = std::invoke_result_t, + std::remove_const_t>{}> +concept InvocableQuantities = QuantitySpec && Quantity && Quantity && + InvokeResultOf; // TODO remove the following when clang diagnostics improve // https://github.com/llvm/llvm-project/issues/96660 @@ -104,7 +105,7 @@ concept CommonlyInvocableQuantities = Quantity && Quantity && HaveCommonReference && std::convertible_to> && std::convertible_to> && - InvocableQuantities; + InvocableQuantities; template concept SameValueAs = (equivalent(get_unit(R1), get_unit(R2))) && std::convertible_to; @@ -128,7 +129,7 @@ MP_UNITS_EXPORT_BEGIN * @tparam R a reference of the quantity providing all information about quantity properties * @tparam Rep a type to be used to represent values of a quantity */ -template Rep = double> +template Rep = double> class quantity { public: Rep numerical_value_is_an_implementation_detail_; ///< needs to be public for a structural type @@ -227,14 +228,14 @@ class quantity { return quantity{*this}; } - template ToRep> + template ToRep> requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr QuantityOf auto in() const { return quantity{*this}; } - template ToRep, detail::UnitCompatibleWith ToU> + template ToRep, detail::UnitCompatibleWith ToU> requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr QuantityOf auto in(ToU) const { @@ -248,14 +249,14 @@ class quantity { return value_cast(*this); } - template ToRep> + template ToRep> requires requires(quantity q) { value_cast(q); } [[nodiscard]] constexpr QuantityOf auto force_in() const { return value_cast(*this); } - template ToRep, detail::UnitCompatibleWith ToU> + template ToRep, detail::UnitCompatibleWith ToU> requires requires(quantity q) { value_cast(q); } [[nodiscard]] constexpr QuantityOf auto force_in(ToU) const { @@ -474,17 +475,15 @@ class quantity { ret::reference}; } - template Q, RepresentationOf Value> - requires(Q::unit == ::mp_units::one) && - detail::InvokeResultOf, Rep, const Value&> + template Q, Representation Value> + requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const Value& rhs) { return lhs + ::mp_units::quantity{rhs}; } - template Q, RepresentationOf Value> - requires(Q::unit == ::mp_units::one) && - detail::InvokeResultOf, Rep, const Value&> + template Q, Representation Value> + requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const Q& rhs) { return ::mp_units::quantity{lhs} + rhs; @@ -501,17 +500,15 @@ class quantity { ret::reference}; } - template Q, RepresentationOf Value> - requires(Q::unit == ::mp_units::one) && - detail::InvokeResultOf, Rep, const Value&> + template Q, Representation Value> + requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] friend constexpr Quantity auto operator-(const Q& lhs, const Value& rhs) { return lhs - ::mp_units::quantity{rhs}; } - template Q, RepresentationOf Value> - requires(Q::unit == ::mp_units::one) && - detail::InvokeResultOf, Rep, const Value&> + template Q, Representation Value> + requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const Q& rhs) { return ::mp_units::quantity{lhs} - rhs; @@ -530,17 +527,15 @@ class quantity { ret::reference}; } - template Q, RepresentationOf Value> - requires(Q::unit == ::mp_units::one) && - detail::InvokeResultOf, Rep, const Value&> + template Q, Representation Value> + requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] friend constexpr Quantity auto operator%(const Q& lhs, const Value& rhs) { return lhs % ::mp_units::quantity{rhs}; } - template Q, RepresentationOf Value> - requires(Q::unit == ::mp_units::one) && - detail::InvokeResultOf, Rep, const Value&> + template Q, Representation Value> + requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] friend constexpr Quantity auto operator%(const Value& lhs, const Q& rhs) { return ::mp_units::quantity{lhs} % rhs; @@ -555,7 +550,7 @@ class quantity { template Q, typename Value> requires(!Quantity) && - (!Reference) && detail::InvokeResultOf, Rep, const Value&> + (!Reference) && detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] friend constexpr QuantityOf auto operator*(const Q& q, const Value& v) { return ::mp_units::quantity{q.numerical_value_ref_in(unit) * v, R}; @@ -563,7 +558,7 @@ class quantity { template Q> requires(!Quantity) && - (!Reference) && detail::InvokeResultOf, const Value&, Rep> + (!Reference) && detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] friend constexpr QuantityOf auto operator*(const Value& v, const Q& q) { return ::mp_units::quantity{v * q.numerical_value_ref_in(unit), R}; @@ -579,7 +574,7 @@ class quantity { template Q, typename Value> requires(!Quantity) && - (!Reference) && detail::InvokeResultOf, Rep, const Value&> + (!Reference) && detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] friend constexpr QuantityOf auto operator/(const Q& q, const Value& v) { MP_UNITS_EXPECTS_DEBUG(v != quantity_values::zero()); @@ -588,7 +583,7 @@ class quantity { template Q> requires(!Quantity) && - (!Reference) && detail::InvokeResultOf, const Value&, Rep> + (!Reference) && detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] friend constexpr QuantityOf auto operator/(const Value& v, const Q& q) { return ::mp_units::quantity{v / q.numerical_value_ref_in(unit), ::mp_units::one / R}; @@ -605,7 +600,7 @@ class quantity { return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit); } - template Q, RepresentationOf Value> + template Q, Representation Value> requires(Q::unit == ::mp_units::one) && std::equality_comparable_with [[nodiscard]] friend constexpr bool operator==(const Q& lhs, const Value& rhs) { @@ -623,7 +618,7 @@ class quantity { return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit); } - template Q, RepresentationOf Value> + template Q, Representation Value> requires(Q::unit == ::mp_units::one) && std::three_way_comparable_with [[nodiscard]] friend constexpr auto operator<=>(const Q& lhs, const Value& rhs) { @@ -650,18 +645,21 @@ template requires requires { { mp_units::get_common_reference(Q1::reference, Q2::reference) } -> mp_units::Reference; typename std::common_type_t; + requires mp_units::RepresentationOf, + mp_units::get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>; } struct std::common_type { using type = mp_units::quantity>; }; -template Value> - requires(Q::unit == mp_units::one) && requires { typename std::common_type_t; } +template + requires(Q::unit == mp_units::one) && + requires { typename mp_units::quantity>; } struct std::common_type { using type = mp_units::quantity>; }; -template Value> - requires(Q::unit == mp_units::one) && requires { typename std::common_type_t; } +template + requires requires { typename std::common_type; } struct std::common_type : std::common_type {}; diff --git a/src/core/include/mp-units/framework/quantity_concepts.h b/src/core/include/mp-units/framework/quantity_concepts.h index 15cdc260b..b402a9270 100644 --- a/src/core/include/mp-units/framework/quantity_concepts.h +++ b/src/core/include/mp-units/framework/quantity_concepts.h @@ -31,7 +31,7 @@ namespace mp_units { -MP_UNITS_EXPORT template Rep> +MP_UNITS_EXPORT template Rep> class quantity; namespace detail { diff --git a/src/core/include/mp-units/framework/quantity_point.h b/src/core/include/mp-units/framework/quantity_point.h index e96220d0d..782b89b69 100644 --- a/src/core/include/mp-units/framework/quantity_point.h +++ b/src/core/include/mp-units/framework/quantity_point.h @@ -172,7 +172,7 @@ template * @tparam Rep a type to be used to represent values of a quantity point */ MP_UNITS_EXPORT template auto PO = default_point_origin(R), - RepresentationOf Rep = double> + RepresentationOf Rep = double> class quantity_point { public: // member types and values @@ -329,14 +329,14 @@ class quantity_point { return ::mp_units::quantity_point{quantity_ref_from(point_origin).in(ToU{}), point_origin}; } - template ToRep> + template ToRep> requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr QuantityPointOf auto in() const { return ::mp_units::quantity_point{quantity_ref_from(point_origin).template in(), point_origin}; } - template ToRep, detail::UnitCompatibleWith ToU> + template ToRep, detail::UnitCompatibleWith ToU> requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr QuantityPointOf auto in(ToU) const { @@ -350,14 +350,14 @@ class quantity_point { return ::mp_units::quantity_point{quantity_ref_from(point_origin).force_in(ToU{}), point_origin}; } - template ToRep> + template ToRep> requires requires(quantity_type q) { value_cast(q); } [[nodiscard]] constexpr QuantityPointOf auto force_in() const { return ::mp_units::quantity_point{quantity_ref_from(point_origin).template force_in(), point_origin}; } - template ToRep, detail::UnitCompatibleWith ToU> + template ToRep, detail::UnitCompatibleWith ToU> requires requires(quantity_type q) { value_cast(q); } [[nodiscard]] constexpr QuantityPointOf auto force_in(ToU) const { diff --git a/src/core/include/mp-units/framework/quantity_point_concepts.h b/src/core/include/mp-units/framework/quantity_point_concepts.h index 08834c9ae..e76836e9b 100644 --- a/src/core/include/mp-units/framework/quantity_point_concepts.h +++ b/src/core/include/mp-units/framework/quantity_point_concepts.h @@ -76,7 +76,7 @@ MP_UNITS_EXPORT template concept PointOriginFor = PointOrigin && QuantitySpecOf; MP_UNITS_EXPORT template auto PO, - RepresentationOf Rep> + RepresentationOf Rep> class quantity_point; namespace detail { diff --git a/src/core/include/mp-units/framework/reference.h b/src/core/include/mp-units/framework/reference.h index 0e209eb8d..10d0597d0 100644 --- a/src/core/include/mp-units/framework/reference.h +++ b/src/core/include/mp-units/framework/reference.h @@ -190,24 +190,21 @@ struct reference { }; -template Rep = std::remove_cvref_t> +template Rep = std::remove_cvref_t> requires(!detail::OffsetUnit) [[nodiscard]] constexpr quantity operator*(FwdRep&& lhs, R r) { return quantity{std::forward(lhs), r}; } -template Rep = std::remove_cvref_t> +template Rep = std::remove_cvref_t> requires(!detail::OffsetUnit) [[nodiscard]] constexpr quantity operator/(FwdRep&& lhs, R) { return quantity{std::forward(lhs), inverse(R{})}; } -template Rep = std::remove_cvref_t> +template Rep = std::remove_cvref_t> requires detail::OffsetUnit [[deprecated( "References using offset units (e.g., temperatures) should be constructed with the `delta` or `absolute` " @@ -217,8 +214,7 @@ operator*(FwdRep&& lhs, R r) return quantity{std::forward(lhs), r}; } -template Rep = std::remove_cvref_t> +template Rep = std::remove_cvref_t> requires detail::OffsetUnit [[deprecated( "References using offset units (e.g., temperatures) should be constructed with the `delta` or `absolute` " @@ -229,7 +225,7 @@ operator/(FwdRep&& lhs, R) } template - requires RepresentationOf, get_quantity_spec(R{}).character> + requires RepresentationOf, get_quantity_spec(R{})> // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) constexpr auto operator*(R, Rep&&) #if __cpp_deleted_function @@ -239,7 +235,7 @@ constexpr auto operator*(R, Rep&&) #endif template - requires RepresentationOf, get_quantity_spec(R{}).character> + requires RepresentationOf, get_quantity_spec(R{})> // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) constexpr auto operator/(R, Rep&&) #if __cpp_deleted_function diff --git a/src/core/include/mp-units/framework/representation_concepts.h b/src/core/include/mp-units/framework/representation_concepts.h index 6a999516d..2edfad8ec 100644 --- a/src/core/include/mp-units/framework/representation_concepts.h +++ b/src/core/include/mp-units/framework/representation_concepts.h @@ -25,6 +25,7 @@ // IWYU pragma: private, include #include #include +#include #ifndef MP_UNITS_IN_MODULE_INTERFACE #ifdef MP_UNITS_IMPORT_STD @@ -165,7 +166,11 @@ MP_UNITS_EXPORT template concept Representation = detail::ScalarRepresentation || detail::ComplexRepresentation || detail::VectorRepresentation || detail::TensorRepresentation; -MP_UNITS_EXPORT template -concept RepresentationOf = detail::IsOfCharacter && Representation; +MP_UNITS_EXPORT template +concept RepresentationOf = + Representation && + ((QuantitySpec && + (detail::QuantityKindSpec || detail::IsOfCharacter)) || + (std::same_as && detail::IsOfCharacter)); } // namespace mp_units diff --git a/src/core/include/mp-units/framework/value_cast.h b/src/core/include/mp-units/framework/value_cast.h index 020424dcd..1d70616c6 100644 --- a/src/core/include/mp-units/framework/value_cast.h +++ b/src/core/include/mp-units/framework/value_cast.h @@ -63,7 +63,7 @@ template> * @tparam ToRep a representation type to use for a target quantity */ template> - requires RepresentationOf && std::constructible_from + requires RepresentationOf && std::constructible_from [[nodiscard]] constexpr quantity value_cast(FwdQ&& q) { return detail::sudo_cast>(std::forward(q)); @@ -81,7 +81,7 @@ template> - requires(convertible(Q::reference, ToU)) && RepresentationOf && + requires(convertible(Q::reference, ToU)) && RepresentationOf && std::constructible_from [[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q) { @@ -89,7 +89,7 @@ template> - requires(convertible(Q::reference, ToU)) && RepresentationOf && + requires(convertible(Q::reference, ToU)) && RepresentationOf && std::constructible_from [[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q) { @@ -148,7 +148,7 @@ template> - requires RepresentationOf && std::constructible_from + requires RepresentationOf && std::constructible_from [[nodiscard]] constexpr quantity_point value_cast(FwdQP&& qp) { return {value_cast(std::forward(qp).quantity_from_origin_is_an_implementation_detail_), @@ -167,7 +167,7 @@ template> - requires(convertible(QP::reference, ToU)) && RepresentationOf && + requires(convertible(QP::reference, ToU)) && RepresentationOf && std::constructible_from [[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp) { @@ -177,7 +177,7 @@ template> - requires(convertible(QP::reference, ToU)) && RepresentationOf && + requires(convertible(QP::reference, ToU)) && RepresentationOf && std::constructible_from [[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp) { diff --git a/test/static/quantity_test.cpp b/test/static/quantity_test.cpp index ba34a1601..adc3cd41e 100644 --- a/test/static/quantity_test.cpp +++ b/test/static/quantity_test.cpp @@ -319,7 +319,7 @@ static_assert(invalid_getter_with_unit_conversion); /////////////////////////////////////// template Rep = double> + RepresentationOf Rep = double> struct child_quantity : quantity { using quantity_type = quantity; static constexpr auto reference = R; From 5097096915e1b94419447621958d0bc79fc4afbb Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 7 Nov 2024 18:42:20 +0100 Subject: [PATCH 6/6] test: lots of tests for complex quantities --- test/static/quantity_test.cpp | 111 +++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/test/static/quantity_test.cpp b/test/static/quantity_test.cpp index adc3cd41e..afcac7d7d 100644 --- a/test/static/quantity_test.cpp +++ b/test/static/quantity_test.cpp @@ -53,6 +53,9 @@ namespace { using namespace mp_units; using namespace mp_units::si::unit_symbols; +#if MP_UNITS_HOSTED +using namespace std::complex_literals; +#endif ////////////////////////////// // quantity class invariants @@ -70,6 +73,10 @@ concept invalid_types = requires { requires !requires { typename Q; }; // bool is not a valid representation type requires !requires { typename Q>; }; // quantity used as Rep requires !requires { typename Q; }; // vector representation expected +#if MP_UNITS_HOSTED + requires !requires { typename Q>; }; // incompatible character + requires !requires { typename Q; }; // incompatible character +#endif }; static_assert(invalid_types); @@ -176,6 +183,17 @@ static_assert(std::convertible_to, quantity, quantity>); static_assert(std::convertible_to, quantity>); +#if MP_UNITS_HOSTED +static_assert(std::constructible_from>, + quantity>>); +static_assert(std::convertible_to>, + quantity>>); +static_assert(std::constructible_from>, + quantity>>); +static_assert(std::convertible_to>, + quantity>>); +#endif + // conversion between different quantities not allowed static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity>); @@ -235,6 +253,12 @@ static_assert(!std::convertible_to, double>); static_assert(std::constructible_from>); static_assert(!std::convertible_to, double>); static_assert(std::constructible_from>); +#if MP_UNITS_HOSTED +static_assert(!std::convertible_to>, std::complex>); +static_assert(std::constructible_from, quantity>>); +static_assert(!std::convertible_to, std::complex>); +static_assert(std::constructible_from, quantity>); +#endif /////////////////////////////////// @@ -278,7 +302,6 @@ static_assert((1. * rad + 1. * deg).in(rad) != 0 * rad); static_assert((1. * rad + 1. * deg).in(deg) != 0 * deg); #if MP_UNITS_HOSTED -using namespace std::complex_literals; static_assert(((2.f + 1if) * isq::voltage_phasor[V]).in(mV).numerical_value_in(mV) == 2000.f + 1000if); static_assert(((2.f + 1if) * isq::voltage_phasor[V]).in(mV).numerical_value_in(V) == 2.f + 1if); static_assert(((2. + 1i) * isq::voltage_phasor[V]).in(mV).numerical_value_in(mV) == 2000. + 1000i); @@ -381,6 +404,9 @@ static_assert(quantity{123}.unit == one); static_assert(quantity{123}.quantity_spec == kind_of); #if MP_UNITS_HOSTED +static_assert(quantity{123. + 1i}.unit == one); +static_assert(quantity{123. + 1i}.quantity_spec == kind_of); + using namespace std::chrono_literals; static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -457,6 +483,21 @@ static_assert((1 * m *= 2 * one).numerical_value_in(m) == 2); static_assert((2 * m /= 2 * one).numerical_value_in(m) == 1); static_assert((7 * m %= 2 * m).numerical_value_in(m) == 1); +#if MP_UNITS_HOSTED +static_assert(((1. + 1i) * V += (1. + 1i) * V).numerical_value_in(V) == 2. + 2i); +static_assert(((2. + 2i) * V -= (1. + 1i) * V).numerical_value_in(V) == 1. + 1i); +static_assert(((1. + 1i) * V += 1. * V).numerical_value_in(V) == 2. + 1i); +static_assert(((2. + 2i) * V -= 1. * V).numerical_value_in(V) == 1. + 2i); +static_assert(((1. + 1i) * V *= 2.).numerical_value_in(V) == 2. + 2i); +static_assert(((2. + 2i) * V /= 2.).numerical_value_in(V) == 1. + 1i); +static_assert(((1. + 1i) * V *= 2. * one).numerical_value_in(V) == 2. + 2i); +static_assert(((2. + 2i) * V /= 2. * one).numerical_value_in(V) == 1. + 1i); +static_assert(((1. + 1i) * V *= 2. + 1i).numerical_value_in(V) == (1. + 1i) * (2. + 1i)); +static_assert(((2. + 2i) * V /= 2. + 1i).numerical_value_in(V) == (2. + 2i) / (2. + 1i)); +static_assert(((1. + 1i) * V *= (2. + 1i) * one).numerical_value_in(V) == (1. + 1i) * (2. + 1i)); +static_assert(((2. + 2i) * V /= (2. + 1i) * one).numerical_value_in(V) == (2. + 2i) / (2. + 1i)); +#endif + // different representation types static_assert((2.5 * m += 3 * m).numerical_value_in(m) == 5.5); static_assert((5.5 * m -= 3 * m).numerical_value_in(m) == 2.5); @@ -469,6 +510,10 @@ static_assert((7.5 * m /= 3 * one).numerical_value_in(m) == 2.5); static_assert((1 * m += 1 * km).numerical_value_in(m) == 1001); static_assert((2000 * m -= 1 * km).numerical_value_in(m) == 1000); static_assert((3500 * m %= 1 * km).numerical_value_in(m) == 500); +#if MP_UNITS_HOSTED +static_assert(((1000. + 1000i) * V += (1. + 1i) * kV).numerical_value_in(V) == 2000. + 2000i); +static_assert(((2000. + 2000i) * V -= (1. + 1i) * kV).numerical_value_in(V) == 1000. + 1000i); +#endif // convertible quantity types static_assert((isq::length(1 * m) += isq::height(1 * m)).numerical_value_in(m) == 2); @@ -530,6 +575,11 @@ concept invalid_compound_assignments = requires() { requires !requires(Q l) { l %= 2 * m; }; requires !requires(Q l) { l %= 2. * m; }; +#if MP_UNITS_HOSTED + // modulo operations on a complex representation type not allowed + requires !requires(Q> l) { l %= (2. + 2i) * V; }; +#endif + // no unit constants requires !requires(Q l) { l += m; }; requires !requires(Q l) { l -= m; }; @@ -558,6 +608,11 @@ concept invalid_binary_operations = requires { requires !requires(Q a, Q b) { a % b; }; requires !requires(Q a, Q b) { b % a; }; +#if MP_UNITS_HOSTED + // no complex modulo + requires !requires(Q> a) { a % (2. + 2i) * V; }; +#endif + // unit constants requires !requires { Q(1) + m; }; requires !requires { Q(1) - m; }; @@ -862,6 +917,19 @@ static_assert(4 / (2 * one) == 2 * one); static_assert(4 * one / 2 == 2 * one); static_assert(4 * one % (2 * one) == 0 * one); +#if MP_UNITS_HOSTED +static_assert(((3. + 3i) * one *= (2. + 2i) * one) == (3. + 3i) * (2. + 2i) * one); +static_assert(((6. + 6i) * one /= (2. + 2i) * one) == (6. + 6i) / (2. + 2i) * one); +static_assert((1. + 1i) * one + (1. + 1i) * one == (2. + 2i) * one); +static_assert((2. + 2i) * one - (1. + 1i) * one == (1. + 1i) * one); +static_assert((2. + 2i) * one * (2. * one) == (4. + 4i) * one); +static_assert((2. + 2i) * ((2. + 2i) * one) == (2. + 2i) * (2. + 2i) * one); +static_assert((2. + 2i) * one * (2. + 2i) == (2. + 2i) * (2. + 2i) * one); +static_assert((4. + 4i) * one / ((2. + 2i) * one) == (4. + 4i) / (2. + 2i) * one); +static_assert((4. + 4i) / ((2. + 2i) * one) == (4. + 4i) / (2. + 2i) * one); +static_assert((4. + 4i) * one / (2. + 2i) == (4. + 4i) / (2. + 2i) * one); +#endif + static_assert(1 * one + 1 == 2); static_assert(1 + 1 * one == 2); static_assert(2 * one - 1 == 1); @@ -873,6 +941,13 @@ static_assert(2.23 - 1 * one == 1.23); static_assert(4 * one % (2) == 0); static_assert(4 % (2 * one) == 0); +#if MP_UNITS_HOSTED +static_assert((1. + 1i) * one + (1. + 1i) == 2. + 2i); +static_assert((1. + 1i) + (1. + 1i) * one == 2. + 2i); +static_assert(2. * one - (1. + 1i) == (1. - 1i)); +static_assert(2. - (1. + 1i) * one == (1. - 1i)); +#endif + static_assert(2 * rad * (2 * rad) == 4 * pow<2>(rad)); // modulo arithmetics @@ -912,6 +987,36 @@ static_assert(is_same_v constexpr bool invalid_comparison = !requires { 2 * R1 == 2 * R2; } && !requires { 2 * R2 == 2 * R1; }; static_assert(invalid_comparison); +#if MP_UNITS_HOSTED +static_assert((1. + 1i) * one == 1. + 1i); +static_assert(1. + 1i != (2. + 2i) * one); +#endif /////////////////////// // ordering operators